package cn.itcast.bos.realms;

import java.util.ArrayList;
import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.itcast.bos.dao.system.PermissionDao;
import cn.itcast.bos.dao.system.RoleDao;
import cn.itcast.bos.dao.system.UserDao;
import cn.itcast.bos.domain.system.Permission;
import cn.itcast.bos.domain.system.Role;
import cn.itcast.bos.domain.system.User;


/**
 * @Description:  Reamls是Shiro与我们应用的安全数据沟通的桥梁（访问安全数据-用户信息，用户权限）
 *   1、实现用户认证   2、实现用户授权
 * @Title: BosRealm.java
 * @date 2018年4月25日 下午12:02:58
 */
@Component("bosRealm")
public class BosRealm extends AuthorizingRealm{

	@Autowired
	private UserDao userDao;
	
	@Autowired
	private RoleDao roleDao;
	
	@Autowired
	private PermissionDao permissionDao;

	/**
	  * @Description: 
	  * @param token subject对象调用login方法参数-用户输入用户名密码令牌
	  * @return 
	*/
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		System.out.println("开始认证");
		//根据用户输入账户名查询数据库中真实密码
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		//用户输入名称
		String username = usernamePasswordToken.getUsername();
		User user = userDao.findByUsername(username);
		if(user==null){
			//用户名错误
			return null;   //框架会抛出异常 未知账户异常
		}
		//比对密码是否正确交给shiro框架 (自己也可以比对但不用,交给框架就可以)
		//参数一：主角  参数二：用户正确密码
		AuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
		return info;   //如果密码比对失败，框架会抛出异常
	}
	
	
	/**
	  * @Description: 给当前登陆用户“Subject”授权     将数据库中的权限转移到代码层
	  *  当使用shiro框架提供url拦截方式验证权限(权限授权过滤器，角色授权过滤器)（调用此方法查询当前用户拥有角色以及权限）完成授权操作.
	  *  当使用shiro框架提供注解方式验证权限（调用此方法查询当前用户拥有角色以及权限）完成授权操作.-有权限调用目标方法，没有权限框架抛出异常
	  *  当使用shiro框架提供页面标签验证权限（调用此方法查询当前用户拥有角色以及权限）完成授权操作.-判断页面中元素是否可见
	*/
	/*protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("开始授权");
		//TODO 现在数据库中没有数据故在此方法中每个用户的权限，角色都一样。
		//后期数据变成动态维护后，根据用户ID查询角色，权限 完成动态授权
				
		//创建授权信息对象（包括用户权限，角色）
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//给当前用户增加权限
		info.addStringPermission("standard_page");
		info.addStringPermission("courier_pageQuery");
		//info.addStringPermission("courier_delete");
		//给当前用户增加角色
		info.addRole("admin");
		return info;
	}*/
	
	
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		System.out.println("开始授权");
		List<Role> roleList = new ArrayList<>();
		List<Permission> permissionList = new ArrayList<>();
		//动态查询数据库
		User user = (User) SecurityUtils.getSubject().getPrincipal();
		//如果是内置管理员账户，有所有角色，所有的权限
		if(user.getUsername().equals("admin")){
			roleList = roleDao.findAll();
			permissionList = permissionDao.findAll();
		} else {
			//其他用户，根据用户id动态查询
			roleList = roleDao.findByUserId(user.getId());
			permissionList = permissionDao.findByUserId(user.getId());
		}
		if(roleList!=null && roleList.size()>0){
			for (Role role : roleList) {
				info.addRole(role.getKeyword());
			}
		}
		if(permissionList!=null && permissionList.size()>0){
			for (Permission permission : permissionList) {
				info.addStringPermission(permission.getKeyword());
			}
		}
		return info;
	}
	
	
	
}
